package com.gemframework.modules.prekit.quartz.service;

import com.gemframework.common.config.quartz.GemQuartzProperties;
import com.gemframework.common.exception.GemException;
import com.gemframework.common.utils.GemBeanUtils;
import com.gemframework.common.utils.GemStringUtils;
import com.gemframework.modules.prekit.quartz.entity.Jobs;
import com.gemframework.modules.prekit.quartz.entity.JobsVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

import static org.quartz.DateBuilder.futureDate;

/**
 * @Title: QuartzManager
 * @Package: com.gemframework.modules.perkit.quartz.service
 * @Date: 2020-06-19 23:47:16
 * @Version: v1.0
 * @Description: Quartz管理操作类
 * @Author: nine QQ 769990999
 * @Copyright: Copyright (c) 2020 wanyong
 * @Company: www.gemframework.com
 */
@Slf4j
@Service
public class QuartzManager {

    private Scheduler scheduler;

    @Autowired
    GemQuartzProperties gemQuartzProperties;

    /**
     * @author jinhaoxun
     * @description 构造器
     * @param scheduler 调度器
     */
    public QuartzManager(Scheduler scheduler){
        this.scheduler = scheduler;
    }


    /**
     * 创建并启动任务
     * @param jobsVo
     * @throws Exception
     */
    public boolean startJob(JobsVo jobsVo){

        String jobUrl = gemQuartzProperties.getJobClassPackagePath()+ "." + jobsVo.getExecuteClassName();
        try {
            Class<? extends Job> aClass = (Class<? extends Job>) Class.forName(jobUrl).newInstance().getClass();
            // 任务名，任务组，任务执行类
            JobDetail job = JobBuilder.newJob(aClass).withIdentity(jobsVo.getJobName(),jobsVo.getJobGroup()).build();
            //任务参数
            Map<String, Object> map = new HashMap<>();
            String jobParams = jobsVo.getJobParams();
            if(StringUtils.isNotBlank(jobParams)){
                if(GemStringUtils.isJSONValid(jobParams)){
                    map = GemBeanUtils.objectToMap(jobParams);
                }else{
                    map.put("param",jobParams);
                }
                // 添加任务参数
                job.getJobDataMap().putAll(map);
            }

            // 创建触发器
            Trigger trigger;
            //Simple
            if(jobsVo.getJobType() == 1){
                // 转换为时间差，秒单位
                int startTime = (int) (jobsVo.getTriggerStartTime().getTime() - System.currentTimeMillis()) / 1000;
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(jobsVo.getTriggerName(),  jobsVo.getTriggerGroup())
                        .startAt(futureDate(startTime, DateBuilder.IntervalUnit.SECOND))
                        .build();
            }else{
                trigger = TriggerBuilder.newTrigger()
                        // 触发器名,触发器组
                        .withIdentity(jobsVo.getTriggerName(), jobsVo.getTriggerGroup())
                        // 触发器时间设定
                        .withSchedule(CronScheduleBuilder.cronSchedule(jobsVo.getTriggerCronExpression()))
                        .build();
            }
            // 调度容器设置JobDetail和Trigger
            scheduler.scheduleJob(job, trigger);
            if (!scheduler.isShutdown()) {
                // 启动
                scheduler.start();
            }
        } catch (Exception e) {
            log.info("Quartz新增任务失败:"+e.getMessage());
            e.printStackTrace();
            throw new GemException(e.getMessage());
        }
        return true;
    }


    /**
     * 修改一个任务的触发时间
     * @param jobs
     */
    public boolean modifyJobTime(Jobs jobs) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobs.getTriggerName(), jobs.getTriggerGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                log.info("没有触发器启动...");
                return false;
            }
            if(trigger instanceof CronTrigger){
                String oldTime = ((CronTrigger) trigger).getCronExpression();
                if (!oldTime.equalsIgnoreCase(jobs.getTriggerCronExpression())) {
                    // 触发器
                    TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                    // 触发器名,触发器组
                    triggerBuilder.withIdentity(jobs.getTriggerName(), jobs.getTriggerGroup());
                    triggerBuilder.startNow();
                    // 触发器时间设定
                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(jobs.getTriggerCronExpression()));
                    // 创建Trigger对象
                    trigger = triggerBuilder.build();
                    // 修改一个任务的触发时间
                    scheduler.rescheduleJob(triggerKey, trigger);
                }
            }
            if(trigger instanceof SimpleTrigger){
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(jobs.getTriggerName(), jobs.getTriggerGroup());

                int oldStartTime = (int) (trigger.getStartTime().getTime() - System.currentTimeMillis()) / 1000;
                int oldStopTime = (int) (trigger.getEndTime().getTime() - System.currentTimeMillis()) / 1000;
                int newStartTime = (int) (jobs.getTriggerStartTime().getTime() - System.currentTimeMillis()) / 1000;
                int newStopTime = (int) (jobs.getTriggerStopTime().getTime() - System.currentTimeMillis()) / 1000;
                if (oldStartTime != newStartTime) {
                    triggerBuilder.startAt(futureDate(newStartTime, DateBuilder.IntervalUnit.SECOND));
                }
                if (oldStopTime != newStopTime) {
                    triggerBuilder.endAt(futureDate(newStopTime, DateBuilder.IntervalUnit.SECOND));
                }
                // 创建Trigger对象
                trigger = triggerBuilder.build();
                // 修改一个任务的触发时间
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("Quartz修改任务失败");
            throw new GemException(e.getMessage());
        }
        return true;
    }


    /**
     * 移除任务（停止）
     * @param jobsVo
     */
    public boolean stopJob(JobsVo jobsVo){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobsVo.getTriggerName(), jobsVo.getTriggerGroup());
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(jobsVo.getJobName(), jobsVo.getJobGroup()));
        } catch (Exception e) {
            log.info("Quartz删除改任务失败");
            throw new GemException(e.getMessage());
        }
        return true;
    }

    /**
     * @description 获取任务状态
     * @param triggerName       触发器名
     * @param triggerGroupName  触发器组名
     * @return Boolean 返回操作结果
     * 获取任务是否存在
     * STATE_BLOCKED 4 阻塞
     * STATE_COMPLETE 2 完成
     * STATE_ERROR 3 错误
     * STATE_NONE -1 不存在
     * STATE_NORMAL 0 正常
     * STATE_PAUSED 1 暂停
     * @throws Exception
     */
    public Enum<Trigger.TriggerState> getStatus(String triggerName, String triggerGroupName){
        try {
            Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(triggerName, triggerGroupName));
            return state;
        } catch (Exception e) {
            log.info("Quartz获取任务是否存在失败");
            return null;
        }
    }


    /**
     * 一键启动所有
     */
    public boolean startAll() {
        try {
            scheduler.start();
        } catch (Exception e) {
            log.info("Quartz启动调度器失败");
            throw new GemException(e.getMessage());
        }
        return true;
    }

    /**
     * 一键停止所有
     */
    public boolean shutdownAll(){
        try {
            if(scheduler.isStarted()){
                scheduler.shutdown(true);
            }
        } catch (Exception e) {
            log.info("Quartz关闭调度器失败");
            throw new GemException(e.getMessage());
        }
        return true;
    }

}